package cc.jq1024.domain.activity.service.partake;

import cc.jq1024.domain.activity.model.aggregate.CreatePartakeOrderAggregate;
import cc.jq1024.domain.activity.model.entity.ActivityEntity;
import cc.jq1024.domain.activity.model.entity.PartakeRaffleActivityEntity;
import cc.jq1024.domain.activity.model.entity.UserRaffleOrderEntity;
import cc.jq1024.domain.activity.model.valobj.ActivityStateVO;
import cc.jq1024.domain.activity.repository.IActivityRepository;
import cc.jq1024.domain.activity.service.IRaffleActivityPartakeService;
import cc.jq1024.types.enums.ResponseCode;
import cc.jq1024.types.exception.AppException;
import cc.jq1024.types.snow.SnowflakeIdGenerator;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * @Author: jia-qiang ljq1024.cc
 * @desc: 抽奖活动领取服务 - 抽象类 - 定义标准流程
 * @Date: 2024-06-18-15:27
 */
@Slf4j
@AllArgsConstructor
public abstract class AbstractRaffleActivityPartake implements IRaffleActivityPartakeService {

    protected final IActivityRepository repository;
    protected final SnowflakeIdGenerator snowflakeIdGenerator;

    protected final SimpleDateFormat dateFormatMonth = new SimpleDateFormat("yyyy-MM");
    protected final SimpleDateFormat dateFormatDay = new SimpleDateFormat("yyyy-MM-dd");


    @Override
    public UserRaffleOrderEntity createOrder(String userId, Long activityId) {
        return createOrder(PartakeRaffleActivityEntity.builder()
                .userId(userId)
                .activityId(activityId)
                .build());
    }

    /**
     * 创建抽奖单；用户参与抽奖活动，扣减活动账户库存，产生抽奖单。如存在未被使用的抽奖单则直接返回已存在的抽奖单。
     *
     * @param partakeRaffleActivityEntity 参与抽奖活动实体对象
     * @return 用户抽奖订单实体对象
     */
    @Override
    public UserRaffleOrderEntity createOrder(PartakeRaffleActivityEntity partakeRaffleActivityEntity) {
        // 0. 获取基本信息
        String userId = partakeRaffleActivityEntity.getUserId();
        Long activityId = partakeRaffleActivityEntity.getActivityId();
        Date currentDate = new Date();

        // 1. 查询活动信息 - 用于校验 - 有效期等(简单校验 - 之间校验即可。复杂校验走责任链)
        ActivityEntity activityEntity = repository.queryRaffleActivityByActivityId(activityId);
        // 校验；活动状态
        if (!ActivityStateVO.open.equals(activityEntity.getState())) {
            throw new AppException(ResponseCode.ACTIVITY_STATE_ERROR.getCode(), ResponseCode.ACTIVITY_STATE_ERROR.getInfo());
        }
        // 校验；活动日期「开始时间 <- 当前时间 -> 结束时间」
        if (activityEntity.getBeginDateTime().after(currentDate) || activityEntity.getEndDateTime().before(currentDate)) {
            throw new AppException(ResponseCode.ACTIVITY_DATE_ERROR.getCode(), ResponseCode.ACTIVITY_DATE_ERROR.getInfo());
        }

        // 2. 查询没有被使用的活动抽奖订单
        UserRaffleOrderEntity userRaffleOrderEntity = repository.queryNoUseRaffleOrder(partakeRaffleActivityEntity);
        if (userRaffleOrderEntity != null) {
            // 直接返回， 不用扣减额度
            log.info("创建参与活动订单【已存在未消费】 userId:{} activityId:{} userRaffleOrderEntity:{}", userId, activityId, JSON.toJSONString(userRaffleOrderEntity));
            return userRaffleOrderEntity;
        }

        // 3. 账户额度过滤 & 返回账户对象
        CreatePartakeOrderAggregate createPartakeOrderAggregate = this.doFilterAccount(userId, activityId, currentDate);

        // 4. 构建用户抽奖订单
        UserRaffleOrderEntity userRaffleOrder = this.buildUserRaffleOrder(userId, activityId, currentDate);

        // 5. 填充抽奖单实体对象
        createPartakeOrderAggregate.setUserRaffleOrderEntity(userRaffleOrder);

        // 6. 保存聚合对象 - 一个领域内的一个聚合是一个事务操作
        repository.saveCreatePartakeOrderAggregate(createPartakeOrderAggregate);

        // 7. 返回结果
        return userRaffleOrder;
    }

    /**
     * 构建用户抽奖订单
     * @param userId 用户ID
     * @param activityId 活动ID
     * @param currentDate 当前时间
     * @return 用户抽奖订单对象
     */
    protected abstract UserRaffleOrderEntity buildUserRaffleOrder(String userId, Long activityId, Date currentDate);

    /**
     * 账户额度过滤 & 返回账户对象
     * @param userId 用户ID
     * @param activityId 活动ID
     * @param currentDate 当前时间
     * @return 账户对象
     */
    protected abstract CreatePartakeOrderAggregate doFilterAccount(String userId, Long activityId, Date currentDate);
}
